Skip to content

feat(spec-specs): EIP-7708 ETH Transfers Emit a Log#2023

Merged
Carsons-Eels merged 21 commits into
ethereum:eips/amsterdam/eip-7708from
Carsons-Eels:eips/amsterdam/eip-7708
Jan 22, 2026
Merged

feat(spec-specs): EIP-7708 ETH Transfers Emit a Log#2023
Carsons-Eels merged 21 commits into
ethereum:eips/amsterdam/eip-7708from
Carsons-Eels:eips/amsterdam/eip-7708

Conversation

@Carsons-Eels
Copy link
Copy Markdown
Contributor

@Carsons-Eels Carsons-Eels commented Jan 14, 2026

🗒️ Description

All ETH-transfers, including transactions, CALL and SELFDESTRUCT emit a log.

Add a LOG3 like functionality that logs all transfers in the Ethereum system for CALL* and SELFDESTRUCT.

🔗 Related Issues or PRs

EIPs#9003

Summary

Update EIP definition in line with comments from Eth Magicians.

Status

✔️ Merged

Proposed Changes

Aspect Original EIP Proposals Accepted?
Log Address 0x00...00 (nil) 0xff...fe (SYSTEM_ADDRESS) ❓ Active Debate1
MAGIC Topic TBD keccak256("Transfer(address,address,uint256)") ✔️ Accepted
Fee Logs Not Included Optional LOG2 after execution ❌ Rejected2
Withdrawals Not Included Covered by EIP-7799 ❌ Rejected3
Add special condition SELFDESTRUCT @ self log Not Included Emit LOG2 ✔️ Accepted
SELFDESTRUCT @ self topic[0] Not Included keccak256('Selfdestruct(address,uint256)') ✔️ Accepted

EIPs#11127

Summary

Clarify SELFDESTRUCT event

Status

✔️ Merged

Proposed Changes

Aspect Pre-merge EIP Proposals Accepted?
SELFDESTRUCT @ self topic[1] from address (zero prefixed to fill uint256) Closed contract_address (zero prefixed to fill uint256) ✔️ Accepted
Add new SELFDESTRUCT @ self case Not Included "Any nonzero-value-holding account closure, after any other logs created by EVM execution, but before charging the EIP-1559 priority fee, in lexicographical order of closed account address" ✔️ Accepted

✅ Checklist

  • All: Ran fast tox checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    uvx tox -e static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered adding an entry to CHANGELOG.md.
  • All: Considered updating the online docs in the ./docs/ directory.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

Little brown bat” by U.S. Fish and Wildlife Service Headquarters, CC BY 2.0

Footnotes

  1. System Address (0xff..fe) is being used for now, but this question is still open and needs to be resolved. A shared call for debate might be the best way to deal with this.

  2. Too much uncertainty about the number of logs produced. A new EIP could be created if this is deemed a valuable addition

  3. Different enough to warrant it's own EIP.

@Carsons-Eels Carsons-Eels self-assigned this Jan 14, 2026
@Carsons-Eels Carsons-Eels added A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) E-easy Experience: easy, good for newcomers C-eip Category: tracking implementation of an EIP P-urgent S-needs-attention Status: needs attention S-needs-discussion Status: needs discussion labels Jan 14, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 14, 2026

Codecov Report

❌ Patch coverage is 99.07834% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.14%. Comparing base (c14e9c9) to head (bf16746).

Files with missing lines Patch % Lines
...ethereum/forks/amsterdam/vm/instructions/system.py 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@                     Coverage Diff                     @@
##           eips/amsterdam/eip-7708    #2023      +/-   ##
===========================================================
+ Coverage                    86.07%   86.14%   +0.07%     
===========================================================
  Files                          599      599              
  Lines                        39527    39491      -36     
  Branches                      3780     3782       +2     
===========================================================
  Hits                         34021    34021              
+ Misses                        4872     4848      -24     
+ Partials                       634      622      -12     
Flag Coverage Δ
unittests 86.14% <99.07%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Carsons-Eels Carsons-Eels force-pushed the eips/amsterdam/eip-7708 branch from d2ee487 to dd32088 Compare January 14, 2026 16:37
Copy link
Copy Markdown
Contributor

@spencer-tb spencer-tb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting the ball rolling! I've been looking at the spec, discussions in magicians & EIPs#9003, and I think we should target a minimal spec for devnet-2. The same as EIPs#9003 but without fee payments/withdrawals:

So we have these 3 triggering the log:

  • Any nonzero-value-transferring transaction, before any other logs created by EVM execution
  • Any nonzero-value CALL, at the time that the value transfer executes
  • Any nonzero-value-transferring SELFDESTRUCT, at the time that the value transfer executes

Using (as in EIPs#9003):

  • SYSTEM_ADDRESS = 0xfffffffffffffffffffffffffffffffffffffffe
  • topics[0] = keccak256('Transfer(address,address,uint256)')

Leaving the following for future discussion and devnets:

  • System address & magic values (topics[0])
  • Fee payment logs
  • Withdrawal logs

Given the above please see comments below.

Ohh and can we make this target an ethereum/eips/amsterdam/eip-7708 branch?

from ..trie import Trie

__all__ = ("Environment", "Evm", "Message")
MAGIC_XACTION_LOG_HASH = keccak256(b"42")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MAGIC_XACTION_LOG_HASH = keccak256(b"42")
TRANSFER_TOPIC = keccak256(b"Transfer(address,address,uint256)")
SYSTEM_ADDRESS = Address(bytes.fromhex("fffffffffffffffffffffffffffffffffffffffe"))

Comment thread src/ethereum/forks/amsterdam/vm/__init__.py
Comment thread src/ethereum/forks/amsterdam/vm/__init__.py Outdated
Comment thread src/ethereum/forks/amsterdam/vm/__init__.py
Comment thread src/ethereum/forks/amsterdam/vm/__init__.py Outdated
Comment on lines +295 to +300
transfer_log(
evm,
message.current_target,
message.caller,
message.value,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think execute_code runs for every contract, including nested CALLs, so CALL logs once in system.py, then again here.

Suggested change
transfer_log(
evm,
message.current_target,
message.caller,
message.value,
)

Following some chats with claude, I think we should put this in process_message_call, inside the success branch:

if message.value > 0: # nonzero-value-transferring transaction from spec
    padded_sender = left_pad_zero_bytes(message.caller, 32)
    padded_recipient = left_pad_zero_bytes(message.current_target, 32)
    tx_transfer_log = Log(
        address=SYSTEM_ADDRESS,
        topics=(
            TRANSFER_TOPIC,
            Hash32(padded_sender),
            Hash32(padded_recipient),
        ),
        data=message.value.to_be_bytes32(),
    )
    logs = (tx_transfer_log,) + logs

With the latter we log for "nonzero-value-transferring transactions" and do not duplicate logs for CALL.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, calls to emit_transfer_log() should go next to calls to move_ether(). There two calls to move_ether(), in selfdestruct() and in process_message(). In selfdestruct() the situation is straightforward.

Unfortunately process_message() doesn't have access to the EVM object, because it is created in execute_code(). I think the best solution is the inline execute_code() into process_message(). No one else calls execute_code() and I can see no reason for the two functions to be distinct.

@spencer-tb spencer-tb added this to the amsterdam milestone Jan 14, 2026
@Carsons-Eels Carsons-Eels marked this pull request as ready for review January 14, 2026 22:45
@danceratopz danceratopz changed the title feat(src): EIP-7708 ETH Transfers Emit a Log feat(spec-specs): EIP-7708 ETH Transfers Emit a Log Jan 15, 2026
@danceratopz danceratopz changed the base branch from forks/amsterdam to eips/amsterdam/eip-7708 January 15, 2026 10:06
@danceratopz
Copy link
Copy Markdown
Member

@Carsons-Eels @spencer-tb just a heads up, I just created a new target branch eips/amsterdam/eip-7708 for this EIP and changed the PR's target branch to point to that.

@spencer-tb
Copy link
Copy Markdown
Contributor

Tagging the EIPs PR: ethereum/EIPs#9003

Copy link
Copy Markdown
Contributor

@petertdavies petertdavies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left a few comments. My opinions on proposed changes to the EIP:

  • Log address change: Sensible and uncontroversial
  • Topic change: Good idea and uncontroversial
  • Withdrawals: This has been deferred to a future EIP for sound technical reasons
  • Fee logs: This needs to be dealt with in the EIPs repo, before getting merged here.

Comment thread src/ethereum/forks/amsterdam/vm/__init__.py Outdated
Comment thread src/ethereum/forks/amsterdam/vm/instructions/system.py Outdated
Comment on lines +295 to +300
transfer_log(
evm,
message.current_target,
message.caller,
message.value,
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, calls to emit_transfer_log() should go next to calls to move_ether(). There two calls to move_ether(), in selfdestruct() and in process_message(). In selfdestruct() the situation is straightforward.

Unfortunately process_message() doesn't have access to the EVM object, because it is created in execute_code(). I think the best solution is the inline execute_code() into process_message(). No one else calls execute_code() and I can see no reason for the two functions to be distinct.

@marioevz
Copy link
Copy Markdown
Member

Needs a rebase to forks/amsterdam to incorporate BAL changes.

jsign pushed a commit to jsign/execution-specs that referenced this pull request Jan 20, 2026
* feat(tests): Add additional invalid inputs

* feat(tests): Add tests for zero gas, 3450 gas

* feat(tests): Test precompiles in traditional range, and one outside range

* feat(tests): Check return status

* feat(tests): Test wrong endianness

* fix(tests): Remove brittle storage check
@Carsons-Eels Carsons-Eels force-pushed the eips/amsterdam/eip-7708 branch 2 times, most recently from f2619e5 to 6f70107 Compare January 20, 2026 18:11
@fselmo
Copy link
Copy Markdown
Contributor

fselmo commented Jan 20, 2026

Another rebase with latest eips/amsterdam/eip-7708 (which is already rebased with latest forks/amsterdam) will fix the static checks here. There were unfortunately some large changes that bubbled up here.

@Carsons-Eels Carsons-Eels force-pushed the eips/amsterdam/eip-7708 branch from 6f70107 to f9ce54a Compare January 20, 2026 21:15
* feat(test): port static context static tests to python

Port STATICCALL tests with zero and non-zero value to precompiles

* feat(test): split into legacy test and high-level API test + parametrize
  - Inspired by comment: ethereum#1960 (comment)
  - Split the unreadable bytecode test from the comment where we can parametrize with all precompiles
  as well as with call_value = [0 and nonzero].

* chore: parametrize CREATE2 from Constantinople (where introduced)

* refactor: address comments from PR ethereum#1960

* feat(tests): Add BAL expectations for static call tests >=Amsterdam

* refactor(test): Update test name, add to BAL test_cases.md

* chore: convert to state_test

---------

Co-authored-by: Mario Vega <marioevz@gmail.com>
)
charge_gas(evm, message_call_gas.cost + extend_memory.cost)

if evm.message.is_static and value != U256(0):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated. It's higher up in the method in line 407.

raise WriteInStaticContext
evm.memory += b"\x00" * extend_memory.expand_by

# OPERATION
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to add this, let's be consistent with CALLCODE, STATICCALL, and DELEGATECALL and add this above the evm.memory += ... line. They include memory expansion as part of the # OPERATION.

@Carsons-Eels Carsons-Eels force-pushed the eips/amsterdam/eip-7708 branch 2 times, most recently from 64417cc to 7d15971 Compare January 22, 2026 04:58
@Carsons-Eels Carsons-Eels force-pushed the eips/amsterdam/eip-7708 branch from 7d15971 to b008409 Compare January 22, 2026 05:03
@Carsons-Eels Carsons-Eels merged commit bfa2cf0 into ethereum:eips/amsterdam/eip-7708 Jan 22, 2026
15 of 16 checks passed
@Carsons-Eels Carsons-Eels deleted the eips/amsterdam/eip-7708 branch January 22, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) C-eip Category: tracking implementation of an EIP E-easy Experience: easy, good for newcomers P-urgent S-needs-attention Status: needs attention S-needs-discussion Status: needs discussion

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants